package com.cms.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cms.entity.Action;
import com.cms.entity.Admin;
import com.cms.entity.Role;
import com.cms.service.ActionService;

@Service
public class ActionServiceImpl extends BaseServiceImpl implements ActionService {
	private static final Logger LOG = LoggerFactory
			.getLogger(ActionServiceImpl.class);

	@Cacheable(value="myCache")
	@Transactional(readOnly = true)
	public List<Action> listActions() {
		return baseDao.find(Action.class);
	}

	@Transactional(readOnly = true)
	public Action loadAction(Integer id) {
		return baseDao.get(Action.class, id);
	}

	@Transactional(readOnly = true)
	public Action getActionByRoles(Set<Role> roles) {
		Action root = baseDao.findByProperty(Action.class, "url", "/").get(0);
		filter(root, roles);
		return root;
	}

	@Transactional(readOnly = true)
	public Action getActionByAuthority(Integer authority) {
		Set<Role> roles = new HashSet<Role>();
		Role role = baseDao.getByProperty(Role.class, "authority", authority);
		if (role != null) {
			roles.add(role);
		}
		return getActionByRoles(roles);
	}

	@Transactional(readOnly = true)
	public Action getActionByUsername(String username) {
		Admin user = baseDao.getByProperty(Admin.class, "username", username);
		if (user == null) {
			return null;
		}
		return getActionByRoles(user.getAuthorities());
	}

	private void filter(Action action, Set<Role> roles) {
		boolean valid = false;
		for (Role role : roles) {
			if (action.getRoles().contains(role)) {
				valid = true;
				break;
			}
		}
		action.setValid(valid);
		if (action.getParent() != null && valid) {
			action.getParent().setValid(valid);
		}
		for (Action child : action.getChildren()) {
			filter(child, roles);
		}
	}

	@Transactional
	public void assignActions(Integer authority, Integer[] actionIds) {
		Role role = baseDao.getByProperty(Role.class, "authority", authority);
		if (role == null) {
			throw new RuntimeException("role not exist");
		}
		baseDao.save(role);
	}

	@Transactional
	public List<Action> listDateActions(String title, Integer from, Integer to) {
		// 查询结果
		List<Object> any = new ArrayList<Object>();
		any.add(Transformers.aliasToBean(Action.class));

		if (StringUtils.isNotBlank(title)) {
			any.add(Restrictions.eq("title", title.trim()));
		}
		any.add(Projections.property("id").as("id"));
		any.add(Projections.property("title").as("title"));
		any.add(Projections.property("url").as("url"));
		any.add(Projections.property("icon").as("icon"));
		any.add(Projections.property("parent").as("parent"));

		List<Action> actions = baseDao.findByAny(Action.class, from, to,
				any.toArray());
		return actions;
	}

	@Transactional
	public Long getCount(String title) {
		// 查询结果
		List<Criterion> any = new ArrayList<Criterion>();
		// 查询条件
		if (StringUtils.isNotBlank(title)) {
			any.add(Restrictions.eq("title", title.trim()));
		}
		return baseDao.countByAny(Action.class,
				any.toArray(new Criterion[any.size()]));
	}

	@Transactional
	public void saveAction(Action action) {
		baseDao.save(action);
	}

	@Transactional
	public Action getAction(Integer id) {
		return baseDao.get(Action.class, id);
	}

	@Transactional
	public void updateAction(Action action) {
		baseDao.update(action);
	}

	@Transactional
	public boolean removeById(Integer id) {
		try {
			Action a = baseDao.load(Action.class, id);
			baseDao.delete(a);
			return true;
		} catch (Exception e) {
			LOG.error(e.toString());
		}
		return false;
	}

	@Transactional
	public Action findActionById(int i) {
		return baseDao.get(Action.class, i);
	}

	@Transactional
	public Action getActionByUrl(String url) {
		return baseDao.getByProperty(Action.class, "url", url);
	}

}
